package cn.zwx.mvcframework.beans.support;

import cn.zwx.mvcframework.beans.config.ZwxBeanDefinition;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.*;

/**
 * 用于读取并且解析扫描到类型信息
 * @author zhangwenxue 
 * @date 2022/4/24 22:23
*/ 
public class ZwxBeanDefinitionReader {
    /**
     * 保存加载到配置文件
     */
    private Properties contextConfig = new Properties();

    /**
     * 保存扫描的结果
     */
    private List<String> registerBeanClasses = new ArrayList<String>();

    public Properties getContextConfig() {
        return contextConfig;
    }

    public ZwxBeanDefinitionReader(String... configLocations) {
        // 加载配置 假设配置只有一个
        this.doLoadConfig(configLocations[0]);
        // 解析扫描到类型信息
        this.doScanner();
    }

    /**
     * 把扫描到类转为BeanDefinition并保存起来
     */
    public List<ZwxBeanDefinition>  loadBeanDefinitions(){
        // TODO 这里不应该是全部类都加载 只加载交个IOC管理的Bean
        List<ZwxBeanDefinition> resultList = new ArrayList<>();
        try {
            for (String registerBeanClass : registerBeanClasses) {
               Class<?> clazz = Class.forName(registerBeanClass);
               if (clazz.isInterface()){
                   continue;
               }
               resultList.add(this.doCreateBeanDefinition(clazz.getSimpleName(),clazz.getName()));
               // 处理实现接口
                Class<?>[] interfaces = clazz.getInterfaces();
                for (Class<?> anInterface : interfaces) {
                    ZwxBeanDefinition zwxBeanDefinition  = this.doCreateBeanDefinition(anInterface.getSimpleName(),clazz.getName());
                    resultList.add(zwxBeanDefinition);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultList;
    }

    /**
     * 转换ZwxBeanDefinition
     * @param beanName 类名
     * @param beanClassName 全限定明
     */
    private ZwxBeanDefinition doCreateBeanDefinition(String beanName, String beanClassName) {
        ZwxBeanDefinition beanDefinition = new ZwxBeanDefinition();
        // Spring默认BeanName是ClassName首字母小写
        beanDefinition.setFactoryBeanName(toLowerFirstCase(beanName));
        beanDefinition.setBeanClassName(beanClassName);
        return beanDefinition;
    }


    private String toLowerFirstCase(String simpleName) {
        char [] chars = simpleName.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

    private void doScanner() {
        String scanPackage = contextConfig.getProperty("scanPackage");
        this.scanPackage(scanPackage);
    }


    private void scanPackage(String scanPackage) {
        // 读取指定目录
        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
        if (Objects.isNull(url)){
            return;
        }
        File classPath = new File(url.getFile());
        // 当成一个文件解析
        File[] files = classPath.listFiles();
        if (Objects.isNull(files)){
            return;
        }
        for (File file : files) {
            if (file.isDirectory()){
                this.scanPackage(scanPackage + "." + file.getName());
            }else {
                // 判断是否是字节码文件
                String name = file.getName();
                if (!name.endsWith(".class")){
                    continue;
                }
                //全类名 = 包名.类名
                String className = scanPackage+"."+name.replaceAll(".class","");
                registerBeanClasses.add(className);
            }
        }
    }

    private void doLoadConfig(String configLocation) {
        // 这里有一个问题需要解决，我们一般配置路径会带classpath：
        // spring里面是一个策略模式去加载 我们这里注解简单粗暴的替换
        try (InputStream in = this.getClass().getClassLoader().getResourceAsStream(configLocation.replace("classpath:",""))){
            // 2.加载配置
            contextConfig.load(in);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
